﻿/** 
 * @filename :	RText.js
 * @author : 	baboo  
 * @description:	Show Related Text
 * 20080716:	添加setUrlTpl外部接口
 * 20081120:  解决使用JSON交互模式时，如果回调函数固定，多个实例会出现回调不对应的问题
 * use it like:
 * new $.RText({
 * 	textInput: $('#RText input'),
 * 	showBox: $('#RTextShow'),
 * 	url: '/get.php?w={0}',
 * 	process: function (o, index) { return '<div class="RTextElement">' + o[0] + '</div>' }
 *	oncheck: function(textInput){}
 * });
 */
$.RText = $({
	__init: function (sets) {
		sets = $.extend({
			noResultText: 'No Result!',	
			hideWhenNoResult: true,
			bgE: false,
			'class': 'RTextElement',
			'classSelected': 'RTextElementSelected',
			delay: 1,
			hideDelay: 0.3,
			valueField: 0,
			useJson: false,
			noCache : false,
			getRetArr : function (j) { return j && j.result },
			getRetWord : function (j) { return j && j.word},
			getRelatedTextObject : false,
			mode: 1	//when mode == 1, before request will check if it has no result
		}, sets);
		var textInput = $E(sets.textInput), showBox = $E(sets.showBox), bgE = sets.bgE && $E(sets.bgE);
		var lastChoosed = null, lastShowValue = null, lastValue = null, oriValue = null, timer = null, hideTimer = null, _t = this;
		var clearTimer = function () {if (timer) clearTimeout(timer); timer = null};
		if (sets.useJson && !sets.jsonCallbackName) {
			sets.jsonCallbackName = $.gid();
		}
 		/**
		  *   Opera Keyup不能捕捉到Down键，所以Opera中绑定了Keyup和keydown两个事件
		  */
		var _onkeydownorup = function (event) { 
			var code = $(event, 'keyCode'); 
			if (event.type == 'keydown') {
				if (code == $.Keys.DOWN) chooseNext();
				return;
			}
			switch(code) {
				case $.Keys.DOWN: if(!$.isOpera) chooseNext();  return; 
				case $.Keys.UP: return chooseNext(true);
				case $.Keys.RETURN:
					hide();
					return (sets.onPressEnter || $.empty)();
 
				 case $.Keys.ESC: return hide();
				 default: checkValue();
			}	
		}; 
		var _onblur = function () { hide(); clearTimer(); $.RText.Mgr.activeInstance = null;};
		/**
		  *  tool func
		  */
		var v = function () {return textInput.$('value').trim().toLowerCase() };  
	
		/**
		  * private func
		  */
		var checkValue = function () {
			var value = v();
			if (lastShowValue == value && showBox.css('display') != 'none') return;
			lastValue = value;
			setHideTimer();
			if (lastValue == '' ||(sets.mode == 1 && $.RText.NoResultPrefix.has(lastValue))) {
				clearHideTimer();
				hide();
				return; 
			}
			$.RText.Mgr.activeInstance = _t;
			if (!sets.delay) return show(lastValue);
			clearTimer ();
			timer = setTimeout(delayShow.bind(null, lastValue), sets.delay * 1000);	
		};
		var setHideTimer = function () {
			if (showBox.css('display') == 'none') return;
			clearHideTimer();
			hideTimer = setTimeout(hide, sets.hideDelay * 1000);	
		};
		var clearHideTimer = function () {
			if (hideTimer != null) {
				clearTimeout(hideTimer);	
				hideTimer = null;
			}
		};
		var delayShow = function (w) { 
			if (w == v()) show(w);	
		}; 
		var show = function (w) {
			//clearHideTimer();
			//如果存在获取相关文本对象的接口函数，则通过该函数获取对象
			if (sets.getRelatedTextObject) {
				return realShow(sets.getRelatedTextObject(w));	
			}
			
			var url = sets.url.format(w.encode());
			if (sets.noCache) url  += '&rand=' + Math.random();
			
			//使用动态Script方法与服务器交互数据
			if (sets.useJson) {
				if (sets.jsonCallbackName) {
					if ( !window[sets.jsonCallbackName]) {
						window[sets.jsonCallbackName] = function ( j) {
							$.RText.Mgr.show(j);
						}
					}
					return new $.Json(url, sets.jsonCallbackName);
				}
				return new $.Json(url, realShow);
			}
			if (sets.noCache) {
				new $.Ajax.Simple(url, {
					method : 'get',
					onSuccess: function (t) {
						realShow($.jeval(t.responseText));	
					}	
				});
			} else {
				$.dataQuery(url, {
					callback: realShow,
					process: function (t) { return $.jeval(t.responseText) }	
				});	
			}
		} ; 
		var realShow = function (o) {
			var w = sets.getRetWord(o);
			var result = sets.getRetArr(o);
			if (!w || w != v() || !result) {
				return;
			}
			lastShowValue = w;
			lastChoosed = null;
			var sb = [];
			if (sets.prefix) sb.push(sets.prefix);
			if (result.length == 0) $.RText.NoResultPrefix.add(w);
			for (var i = 0; i < result.length; i ++) {
				sb.push(sets.process(result[i], i));	
			}
			if (result.length == 0) {
				if (sets.hideWhenNoResult) return;
				sb.push(sets.noResultText);
			}
			clearHideTimer();
			if (sets.suffix) sb.push(sets.suffix);
			showBox.html(sb.join(''));
			(showBox.find('>*.' + sets['class']) || []).each(
				function (e, i) { 
					e. title = result[i][sets.valueField];
					e.onmouseover = function() {choose(e, true)};
					e.onmousedown = function (){check(e.title)};	
				}
			);
			showBox.$('$show');
			if (bgE) {
				bgE.css('height:' + showBox[0].offsetHeight + 'px').$('$show');
				var iframe = bgE.find('iframe');
				if (iframe) iframe.css('height:' + showBox[0].offsetHeight + 'px');
			}
		};
		var hide = function () {
			if (showBox.css('display') == 'none') return;
			if (bgE) bgE.$('$hide');
			showBox.$('$hide');
			sets.onHide && sets.onHide();
			lastChoosed = null;
		};
		/**
		  *  public function
		  */
		var activated = false;
		this.activate = function () {
			if (activated) return;
			if ($.isOpera) {
				textInput.keydown(_onkeydownorup);
			} 
			textInput.keyup(_onkeydownorup); 
			textInput.blur(_onblur);
			activated = true;
		};
		
		this.disable = function () {
			if (!activated) return;
			if ($.isOpera) {
				textInput.$keydown(_onkeydownorup);	
			} 
			textInput.$keyup(_onkeydownorup);	
			textInput.$blur(_onblur );
			clearTimer();
			activated = false;	
		};	
		
		this.setUrlTpl = function (newUrl) {
			sets.url = newUrl;
			lastShowValue=null;
			lastValue=null;
			if (sets.mode == 1) $.RText.NoResultPrefix.length = 0;
		};
		var check = function (w) {
			lastValue = w;
			textInput.$('value', w);
			hide();	
			if (sets.oncheck)  sets.oncheck(textInput);
		};
		
		var unchoose = function (o) {
			$.Dom._class(o,  '-' + sets['classSelected']);
		}; 
		var choose = function (o, doNotChangeValue) {
			if (lastChoosed) unchoose(lastChoosed);
			if (o === null) {
				lastChoosed = null;
				return textInput.$('value',  oriValue || '');
			}
			$.Dom._class(o, sets['classSelected']);
			lastChoosed = o;
			if (!doNotChangeValue) {
				var w = o.title;
				lastValue = w.toLowerCase();
				textInput.$('value', w);
			}
		};
		this.choose = choose;
		var chooseNext = function (up) { 
			if (showBox.css('display') == 'none') return;
			var es = showBox.find('*.' + sets['class']);
			if (!es) return;
			if (lastChoosed == null) {
				oriValue = textInput.$('value');
				if (up) return choose(es.elements.last());
				return choose(es[0]);
			}
			
			var i;
			for (i = 0; i < es.length; i ++) {
				if (lastChoosed == es[i]) break;
			}
			if (up) {
				if (i == 0) return choose(null);	
				return choose(es[--i]);
			}
			if (i == es.length - 1) return choose(null);
			return choose(es[++i]);
		} ;
		this.__show = realShow;
		this.activate();
	}
});
$.RText.NoResultPrefix = {
	list: [],
	add: function (w) { this.list.push(w) },
	has: function (w) {
		if(!w) return false;
		for (var i = 0; i < this.list.length; i ++) {
			if (w.indexOf(this.list[i]) == 0) return true;	
		}	
		return false;
	}
};
//为解决使用script对象与服务器交互数据，回调方法固定而实例有多个的问题
$.RText.Mgr = {
	activeInstance : null,
	show : function (j) {
		if (this.activeInstance) {
			this.activeInstance.__show(j);	
		}
	}
};
$.RText.version = 20081120;